/**
 * 
 */
package com.googlecode.xcarve.coder;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.MessageToByteEncoder;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.Lists;
import com.googlecode.xcarve.enums.MessageType;
import com.googlecode.xcarve.object.NettyMessage;

/**
 * @author xinyun.d
 *
 */
public class NettyCodecAdapter{
	
 
	private final Coder coder;
	private final NettyEncodeHandler encoderHandler = new NettyEncodeHandler();
	private final NettyDecodeHandler decoderHandler = new NettyDecodeHandler(1024<<10, 3, 4);
	private static final List<Byte>  unNeedBody = Lists.newArrayList();
	static{
		unNeedBody.add(MessageType.HANDSHAK_REQ.value);
		unNeedBody.add(MessageType.HANDSHAK_RESP.value);
	}
	static final Logger logger = LoggerFactory.getLogger(NettyCodecAdapter.class);
	
	public NettyCodecAdapter(String code){
		 this.coder = CoderFactory.getCoder(code);
	}
 
	public NettyEncodeHandler getEncoderHandler() {
		return encoderHandler;
	}
	
	public NettyDecodeHandler getDecoderHandler() {
		return decoderHandler;
	}
	
	public class NettyEncodeHandler extends MessageToByteEncoder<NettyMessage>{
		  
		/* (non-Javadoc)
		 * @see io.netty.handler.codec.MessageToByteEncoder#encode(io.netty.channel.ChannelHandlerContext, java.lang.Object, io.netty.buffer.ByteBuf)
		 */
		@Override
		protected void encode(ChannelHandlerContext ctx, NettyMessage msg,
				ByteBuf buf) throws Exception {
			 if(msg==null || msg.getHeader()==null){
				 logger.info("message is invalid. msg={}",msg);
				 return;
			 }
			 try {
				 coder.encode(msg, buf);
			} catch (Exception e) {
				logger.error("encoder message error.",e);
				throw new RuntimeException(e);
			}
		}
		
		@Override
		public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
				throws Exception {
			ctx.fireExceptionCaught(cause);
//			logger.error("catched exception when encoding message . ",cause);
		}
	}
	
	public class NettyDecodeHandler extends LengthFieldBasedFrameDecoder{
 
		 
		public NettyDecodeHandler(int maxFrameLength, int lengthFieldOffset,
				int lengthFieldLength) {
			super(maxFrameLength, lengthFieldOffset, lengthFieldLength);
		}

		@Override
		protected Object decode(ChannelHandlerContext ctx, ByteBuf in)
				throws Exception {
			ByteBuf frame = (ByteBuf) super.decode(ctx, in);
			if(frame == null || frame.readableBytes()<=4){
				logger.debug("illegal message request.");				
				return null;
			}
			try {
				return coder.decode(frame);
			} catch (Exception e) {
				logger.error("decode message error." , e);
			}
			return null;
		}
		
		/* (non-Javadoc)
		 * @see io.netty.channel.ChannelHandlerAdapter#exceptionCaught(io.netty.channel.ChannelHandlerContext, java.lang.Throwable)
		 */
		@Override
		public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
				throws Exception {
			ctx.fireExceptionCaught(cause);
//			logger.error("catched exception when decoding message . ",cause);
		}
		
	}
	
 

}
